//
//  PictureRender.m
//  MyOpenGLESLearn_iOS
//
//  Created by Gaomingyang on 2021/4/15.
//

#import "PictureRender.h"
#import "ShaderProgram.h"

#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
NSString *const kPictureVertexShaderString = SHADER_STRING
(
 attribute vec4 vPosition;
 attribute vec2 vTextureCoords;
 
 varying vec2 TextureCoordsVarying;
 varying vec4 gPosition;
 
 void main (void) {
     gl_Position = vPosition;
     TextureCoordsVarying = vTextureCoords;
     gPosition = vPosition;
 }
 );
#else

#endif

#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
NSString *const kPictureFragmentShaderString = SHADER_STRING
(
 precision mediump float;

 uniform sampler2D sTexture;
 
 uniform int vChangeType;
 uniform vec3 vChangeColor;
 uniform float uXY;
 
 varying vec2 TextureCoordsVarying;
 varying vec4 gPosition;
 
 void modifyColor(vec4 color){
     color.r=max(min(color.r,1.0),0.0);
     color.g=max(min(color.g,1.0),0.0);
     color.b=max(min(color.b,1.0),0.0);
     color.a=max(min(color.a,1.0),0.0);
 }
 
 void main (void) {
     vec4 mask = texture2D(sTexture, TextureCoordsVarying);
    if(vChangeType == 1){
        float c=mask.r*vChangeColor.r+mask.g*vChangeColor.g+mask.b*vChangeColor.b;
        gl_FragColor=vec4(c,c,c,mask.a);
    }else if(vChangeType == 2){
        vec4 deltaColor = mask+vec4(vChangeColor,0.0);
        modifyColor(deltaColor);
        gl_FragColor=deltaColor;
    }else if(vChangeType == 3){
        vec4 deltaColor = mask+vec4(vChangeColor,0.0);
        modifyColor(deltaColor);
        gl_FragColor=deltaColor;
    }else if(vChangeType == 4){
        mask+=texture2D(sTexture,vec2(TextureCoordsVarying.x-vChangeColor.r,TextureCoordsVarying.y-vChangeColor.r));
        mask+=texture2D(sTexture,vec2(TextureCoordsVarying.x-vChangeColor.r,TextureCoordsVarying.y+vChangeColor.r));
        mask+=texture2D(sTexture,vec2(TextureCoordsVarying.x+vChangeColor.r,TextureCoordsVarying.y-vChangeColor.r));
        mask+=texture2D(sTexture,vec2(TextureCoordsVarying.x+vChangeColor.r,TextureCoordsVarying.y+vChangeColor.r));
        mask+=texture2D(sTexture,vec2(TextureCoordsVarying.x-vChangeColor.g,TextureCoordsVarying.y-vChangeColor.g));
        mask+=texture2D(sTexture,vec2(TextureCoordsVarying.x-vChangeColor.g,TextureCoordsVarying.y+vChangeColor.g));
        mask+=texture2D(sTexture,vec2(TextureCoordsVarying.x+vChangeColor.g,TextureCoordsVarying.y-vChangeColor.g));
        mask+=texture2D(sTexture,vec2(TextureCoordsVarying.x+vChangeColor.g,TextureCoordsVarying.y+vChangeColor.g));
        mask+=texture2D(sTexture,vec2(TextureCoordsVarying.x-vChangeColor.b,TextureCoordsVarying.y-vChangeColor.b));
        mask+=texture2D(sTexture,vec2(TextureCoordsVarying.x-vChangeColor.b,TextureCoordsVarying.y+vChangeColor.b));
        mask+=texture2D(sTexture,vec2(TextureCoordsVarying.x+vChangeColor.b,TextureCoordsVarying.y-vChangeColor.b));
        mask+=texture2D(sTexture,vec2(TextureCoordsVarying.x+vChangeColor.b,TextureCoordsVarying.y+vChangeColor.b));
        mask/=13.0;
        gl_FragColor = mask;
    }else if(vChangeType == 5){
        float dis = distance(vec2(gPosition.x,gPosition.y/uXY),vec2(vChangeColor.r,vChangeColor.g));
                    if(dis < vChangeColor.b){
                        mask = texture2D(sTexture,vec2(TextureCoordsVarying.x/2.0+0.25,TextureCoordsVarying.y/2.0+0.25));
                    }
        gl_FragColor = mask;
    }else {
        gl_FragColor = vec4(mask.rgb, 1.0);
    }
 }
 );
#else

#endif

/**
 定义顶点类型
 */
typedef struct {
    GLKVector3 positionCoord; // (X, Y, Z)
    GLKVector2 textureCoord; // (U, V)
} SenceVertex;

@interface PictureRender()<GLKViewDelegate>
{
    // Render
    GLuint  _program;

}
@property (strong, nonatomic) ShaderProgram* shaderProcessor;
@property (strong, nonatomic) EAGLContext* context;
@property (strong, nonatomic) GLKView* glkView;

@property (nonatomic,assign) SenceVertex *vertices; // 顶点数组

@property (nonatomic,assign) PictureRenderFilter filter;//
@end
struct AttributeHandles
{
    GLint   vPosition;
    GLint   vTextureCoords;
};
struct UniformHandles
{
    GLuint  sTexture;
    GLuint  vChangeType;
    GLuint  vChangeColor;
    GLuint  uXY;
};
@implementation PictureRender
{
    struct AttributeHandles _attributes;
    struct UniformHandles   _uniformHandles;
}
-(void)dealloc{
    if ([EAGLContext currentContext] == self.context) {
        [EAGLContext setCurrentContext:nil];
    }
    // C语言风格的数组，需要手动释放
    if (_vertices) {
        free(_vertices);
        _vertices = nil;
    }
}
- (instancetype)initWithGLKView:(GLKView *)glkView{
    self = [super init];
    if (self) {
        [self commonInitWithGLKView:glkView];
    }
    return self;
}
-(void)commonInitWithGLKView:(GLKView *)glkView{
    [self initOpenglESWithGLKView:glkView];
}
-(void)initOpenglESWithGLKView:(GLKView *)glkView{
    self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    
    // Setup View
    self.glkView = glkView;
    self.glkView.delegate = self;
    self.glkView.context = self.context;
    self.glkView.opaque = YES;
    self.glkView.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
    self.glkView.drawableDepthFormat = GLKViewDrawableDepthFormat16;
    
    // Initialize Class Objects
    self.shaderProcessor = [[ShaderProgram alloc] init];
    self.filter = PictureRenderFilter_NONE;
    [self resetupOpenGLES];
}
- (void)resetupOpenGLES
{
    [EAGLContext setCurrentContext:self.context];
    // 创建顶点数组
    self.vertices = malloc(sizeof(SenceVertex) * 4); // 4 个顶点
    
    self.vertices[0] = (SenceVertex){{-1, 1, 0}, {0, 1}}; // 左上角
    self.vertices[1] = (SenceVertex){{-1, -1, 0}, {0, 0}}; // 左下角
    self.vertices[2] = (SenceVertex){{1, 1, 0}, {1, 1}}; // 右上角
    self.vertices[3] = (SenceVertex){{1, -1, 0}, {1, 0}}; // 右下角
    
    // Enable depth test
    glEnable(GL_DEPTH_TEST);
    // Create the GLSL program
    _program = [self.shaderProcessor BuildProgram:[kPictureVertexShaderString cStringUsingEncoding:NSUTF8StringEncoding] with:[kPictureFragmentShaderString cStringUsingEncoding:NSUTF8StringEncoding]];

    // end create program
    glUseProgram(_program);
    
    // 获取 shader 中的参数，然后传数据进去
    _attributes.vPosition = glGetAttribLocation(_program, "vPosition");
    _attributes.vTextureCoords = glGetAttribLocation(_program, "vTextureCoords");
    
    // 注意 Uniform 类型的获取方式
    _uniformHandles.sTexture = glGetUniformLocation(_program, "sTexture");
    _uniformHandles.vChangeType = glGetUniformLocation(_program, "vChangeType");
    _uniformHandles.vChangeColor = glGetUniformLocation(_program, "vChangeColor");
    _uniformHandles.uXY = glGetUniformLocation(_program, "uXY");
}

- (void)setDisplay{
    [self.glkView display];
}
-(void)setPictureFilter:(PictureRenderFilter )filter{
    self.filter = filter;
}
# pragma mark - GLKView Delegate
- (void)update:(id)sender {
    [self.glkView display];
}

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    // Clear Buffers
    glClearColor(0.05, 0.05, 0.05, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    // 读取纹理
    NSString *imagePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"miaomiao.png"];
    UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
    GLuint textureID = [self.shaderProcessor createTextureWithImage:image];
    
    // 将纹理 ID 传给着色器程序
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textureID);
    glUniform1i(_uniformHandles.sTexture, 0);  // 将 textureSlot 赋值为 0，而 0 与 GL_TEXTURE0 对应，这里如果写 1，上面也要改成 GL_TEXTURE1
    // 创建顶点缓存
    GLuint vertexBuffer;
    glGenBuffers(1, &vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    GLsizeiptr bufferSizeBytes = sizeof(SenceVertex) * 4;
    glBufferData(GL_ARRAY_BUFFER, bufferSizeBytes, self.vertices, GL_STATIC_DRAW);
    
    // 设置顶点数据
    glEnableVertexAttribArray(_attributes.vPosition);
    glVertexAttribPointer(_attributes.vPosition, 3, GL_FLOAT, GL_FALSE, sizeof(SenceVertex), NULL + offsetof(SenceVertex, positionCoord));
    
    // 设置纹理数据
    glEnableVertexAttribArray(_attributes.vTextureCoords);
    glVertexAttribPointer(_attributes.vTextureCoords, 2, GL_FLOAT, GL_FALSE, sizeof(SenceVertex), NULL + offsetof(SenceVertex, textureCoord));
    
    glUniform1i(_uniformHandles.vChangeType, (GLuint)self.filter);
    float *changeColor = [self getFilterDataWithFilterType:self.filter];
//    glUniform3f(_uniformHandles.vChangeColor, changeColor[0], changeColor[1], changeColor[2]);
    glUniform3fv(_uniformHandles.vChangeColor, 1, changeColor);
    
    CGFloat width = [UIScreen mainScreen].bounds.size.width;
    CGFloat height = [UIScreen mainScreen].bounds.size.height;
    float sWidthHeight = width/(float)height;
    
    glUniform1f(_uniformHandles.uXY, sWidthHeight);
    NSLog(@"_uniformHandles.vChangeColor:%lu",(unsigned long)_uniformHandles.vChangeColor);

    NSLog(@"_uniformHandles.uXY:%lu",(unsigned long)_uniformHandles.uXY);

    NSLog(@"self.filter:%lu",(unsigned long)self.filter);
    NSLog(@" uXY:%f",sWidthHeight);
    // 开始绘制
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    
    // 将绑定的渲染缓存呈现到屏幕上
    [self.context presentRenderbuffer:GL_RENDERBUFFER];
    
    // 删除顶点缓存
    glDeleteBuffers(1, &vertexBuffer);
    vertexBuffer = 0;
}

# pragma mark - GLKViewController Delegate
- (void)glkViewControllerUpdate:(GLKViewController *)controller
{
}

-(float *)getFilterDataWithFilterType:(PictureRenderFilter )filter{
    float * result = malloc(sizeof(float)*(3));
    if (filter == PictureRenderFilter_NONE) {
        result[0] = 0.0f;
        result[1] = 0.0f;
        result[2] = 0.0f;
    }else if (filter == PictureRenderFilter_GRAY) {
        result[0] = 0.299f;
        result[1] = 0.587f;
        result[2] = 0.114f;
    }else if (filter == PictureRenderFilter_COOL) {
        result[0] = 0.0f;
        result[1] = 0.0f;
        result[2] = 0.1f;
    }else if (filter == PictureRenderFilter_WARM) {
        result[0] = 0.1f;
        result[1] = 0.1f;
        result[2] = 0.0f;
    }else if (filter == PictureRenderFilter_BLUR) {
        result[0] = 0.006f;
        result[1] = 0.004f;
        result[2] = 0.002f;
    }else if (filter == PictureRenderFilter_MAGN) {
        result[0] = 0.0f;
        result[1] = 0.0f;
        result[2] = 0.4f;
    }
    
    return  result;
}
@end
